#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "Clock.h"
#include "DirectorTrabajos.h"

#define OK 0
#define ERROR 1
#define LINEALNG 1024

#define PRIORIDAD_MAX 1000
#define POTENCIA_PROCESO_MAX 10
#define REQUERIMIENTO_MEMORIA_MAX 1024000000
#define PATH_NULO ""
#define TIEMPO_MIN 0

//==============================================================================

typedef FILE* tStream;

typedef void (*tFcnComando) (char* comando, tClock pClock, tDirectorTrabajos pDirector);

tStream inicializarEntrada (int argc, char* argv[]);

void finalizarEntrada(tStream pEntrada);

void fcnComando (char* comando, tClock pClock, tDirectorTrabajos pDirector);

void fcnComandoTraceable (char* comando, tClock pClock, tDirectorTrabajos pDirector);

//==============================================================================

int main(int argc, char* argv[]) {
    
    int error = OK;
    tStream entrada = inicializarEntrada(argc, argv);
    
    if (NULL != entrada)
    {
        // Inicializo el clock de sincronizacion.
        tClock clock;
        clockCrear(&clock);
        
        // Inicializo el director de trabajos.
        tDirectorTrabajos director;
        directorTrabajosCrear(&director);
        
        // Identifico el modo de operacion seleccionado.
        tFcnComando comando = &fcnComando;
        if (argc > 2)
            if (0 == strcmp (argv[2], "verbose"))
                comando = &fcnComandoTraceable;
        
        // Identifico el modo de seleccion de comandos.
        char comandoIn[LINEALNG];
        while (fgets (comandoIn, LINEALNG, entrada)) 
            comando (comandoIn, clock, director);
        
        // Finalizo el director de trabajos.
        directorTrabajosDestruir(director);
        
        // Finalizo el clock de sincronizacion.
        clockCancelarSuscripciones (clock);
        clockDestruir(clock);
    }
    else
        error = ERROR;
    
    finalizarEntrada(entrada);
            
    return error;
}

//==============================================================================

tStream inicializarEntrada (int argc, char* argv[]){
    
    tStream stream = NULL;
    if (argc > 1)
      stream = fopen (argv[1], "r");  
    else if (argc == 1)
        stream = stdin;
  
    return stream;
}

//------------------------------------------------------------------------------

void finalizarEntrada(tStream pEntrada){
    if (pEntrada)
        if (pEntrada != stdin)
            fclose (pEntrada);
}

//------------------------------------------------------------------------------
    
void fcnComando (char* comando, tClock pClock, tDirectorTrabajos pDirector){
    
    if (strlen(comando) > 0)
    {
        char *token;
        char seps[]   = " ";
        char* tmp;

        token = strtok( comando, seps );

        if (NULL != token)
        {
            if (0 == strcmp("NODE", token))
            {
                token = strtok( NULL, seps );
                if (NULL != token)
                    directorTrabajosNode(pDirector, strtoul(token, &tmp, 10));
            }
            else if (0 == strcmp ("JOB", token))
            {
                int prioridad = PRIORIDAD_MAX
                ,   potenciaProceso = POTENCIA_PROCESO_MAX;
                unsigned long int requerimientoMemoria = REQUERIMIENTO_MEMORIA_MAX;
                char* pathEjecutable = PATH_NULO;
                tTiempo tiempoEjecucion = TIEMPO_MIN;
                
                token = strtok (NULL, seps);
                if (NULL != token)
                    prioridad = atoi(token);
                
                token = strtok (NULL, seps);
                if (NULL != token)
                    potenciaProceso = atoi(token);
                
                token = strtok (NULL, seps);
                if (NULL != token)
                    requerimientoMemoria = strtoul(token, &tmp, 10);
                
                token = strtok (NULL, seps);
                if (NULL != token)
                    pathEjecutable = token;
                
                token = strtok (NULL, seps);
                if (NULL != token)
                    tiempoEjecucion = (tTiempo) atoi(token);
                
                directorTrabajosJob(pDirector, prioridad, potenciaProceso, requerimientoMemoria, pathEjecutable, tiempoEjecucion);
                
            }
            else if (0 == strcmp ("ON", token))
            {
                token = strtok(NULL, seps);
                if (NULL != token)
                    directorTrabajosOn(pDirector, atoi(token));
            }
            else if (0 == strcmp ("OFF", token))
            {
                token = strtok(NULL, seps);
                if (NULL != token)
                    directorTrabajosOff(pDirector, atoi(token));
            }
            else if (0 == strcmp ("QUERY", token))
            {
                token = strtok(NULL, seps);
                if (NULL != token)
                    directorTrabajosQuery(pDirector, atoi(token));                
            }
            else if (0 == strcmp ("RUN", token))
            {
                token = strtok(NULL, seps);
                if (NULL != token)
                {
                    tTiempo ticks = (tTiempo) atoi(token);
                    while (ticks > 0)
                    {
                        directorTrabajosRefrescar(pDirector);
                        clockCorrer(pClock, 1);
                        directorTrabajosRefrescar(pDirector);
                        ticks--;
                    }
                }
            }
        }
    }
}

//------------------------------------------------------------------------------

void fcnComandoTraceable (char* comando, tClock pClock, tDirectorTrabajos pDirector){
    
    if (strlen(comando) > 0)
    {
        char *token;
        char seps[]   = " ";
        char* tmp;

        token = strtok( comando, seps );

        if (NULL != token)
        {
            if (0 == strcmp("NODE", token))
            {
                token = strtok( NULL, seps );
                if (NULL != token)
                    directorTrabajosNode(pDirector, strtoul(token, &tmp, 10));
            }
            else if (0 == strcmp ("JOB", token))
            {
                int prioridad = PRIORIDAD_MAX
                ,   potenciaProceso = POTENCIA_PROCESO_MAX;
                unsigned long int requerimientoMemoria = REQUERIMIENTO_MEMORIA_MAX;
                char* pathEjecutable = PATH_NULO;
                tTiempo tiempoEjecucion = TIEMPO_MIN;
                
                token = strtok (NULL, seps);
                if (NULL != token)
                    prioridad = atoi(token);
                
                token = strtok (NULL, seps);
                if (NULL != token)
                    potenciaProceso = atoi(token);
                
                token = strtok (NULL, seps);
                if (NULL != token)
                    requerimientoMemoria = strtoul(token, &tmp, 10);
                
                token = strtok (NULL, seps);
                if (NULL != token)
                    pathEjecutable = token;
                
                token = strtok (NULL, seps);
                if (NULL != token)
                    tiempoEjecucion = (tTiempo) atoi(token);
                
                printf ("\nJOB [Path: %s][Potencia Proceso: %d][Prioridad: %d][Memora Requerida: %lu][Tiempo Ejecucion: %d]"
                        ,pathEjecutable
                        ,potenciaProceso
                        ,prioridad
                        ,requerimientoMemoria
                        ,tiempoEjecucion);
                
                directorTrabajosJob(pDirector, prioridad, potenciaProceso, requerimientoMemoria, pathEjecutable, tiempoEjecucion);
                
            }
            else if (0 == strcmp ("ON", token))
            {
                token = strtok(NULL, seps);
                if (NULL != token)
                {
                    printf ("\nON %d", atoi(token));
                    directorTrabajosOn(pDirector, atoi(token));
                }
            }
            else if (0 == strcmp ("OFF", token))
            {
                token = strtok(NULL, seps);
                if (NULL != token)
                {
                    printf ("\nOFF %d", atoi(token));                    
                    directorTrabajosOff(pDirector, atoi(token));
                }
            }
            else if (0 == strcmp ("QUERY", token))
            {
                token = strtok(NULL, seps);
                if (NULL != token)
                {
                    printf ("\nQUERY %d => ", atoi(token));                    
                    directorTrabajosQuery(pDirector, atoi(token));                
                }
            }
            else if (0 == strcmp ("RUN", token))
            {
                token = strtok(NULL, seps);
                if (NULL != token)
                {
                    tTiempo ticks = (tTiempo) atoi(token);
                    
                    while (ticks > 0)
                    {
                        printf ("\n==================================================");
                        printf ("==================================================\n");
                        directorTrabajosImprimir(pDirector, stdout);
                        printf ("\n----\nRefrescar...");
                        directorTrabajosRefrescar(pDirector);
                        printf ("\n----\n");
                        directorTrabajosImprimir(pDirector, stdout);
                        printf ("\n--------------------------------------------------\n");
                        printf ("tick: %d", ticks);
                        clockCorrer(pClock, 1);
                        printf ("\n--------------------------------------------------\n");
                        directorTrabajosImprimir(pDirector, stdout);
                        printf ("\n----\nRefrescar...");
                        directorTrabajosRefrescar(pDirector);                    
                        printf ("\n----\n");
                        directorTrabajosImprimir(pDirector, stdout);
                        printf ("\n==================================================");
                        printf ("==================================================\n"); 
                    
                        ticks--;
                    }
                }
            }
        }
    }
}
